package com.shiguiwu.springboot3.websocket;

import cn.hutool.json.JSONUtil;
import com.shiguiwu.springboot3.dto.request.ChatMessageReq;
import com.shiguiwu.springboot3.dto.response.ReplyResponse;
import com.shiguiwu.springboot3.service.ChatMessageService;
import com.shiguiwu.springboot3.service.ConversationService;
import com.shiguiwu.springboot3.service.RedisService;
import com.shiguiwu.springboot3.util.MemberContextUtils;
import io.swagger.v3.core.util.Json;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

//@Component
@Configuration
@Slf4j
public class CustomTextWebSocketHandler extends TextWebSocketHandler {

    private final Map<Long, WebSocketSession> onlineSessions = new ConcurrentHashMap<>();

    @Autowired
    private RedisService redisService;

    @Autowired
    private ChatMessageService chatMessageService;

    @Autowired
    private ConversationService conversationService;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        // 客户端连接成功时调用
        log.info("新的WebSocket连接建立: {}", session.getId());

        String userId = (String) session.getAttributes().get("userId");
        if (userId != null) {
            // 关键：将新会话存入Map
            onlineSessions.put(Long.parseLong(userId), session);
            String instanceId = System.getenv("INSTANCE_ID"); // 每个实例的唯一ID
            //onlineSessions.put(userId, session);
            redisService.setHashValue("ws:online_users", userId, instanceId);
        }

    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {

        String userId = (String) session.getAttributes().get("userId");
        String instanceId = (String) redisService.getHashValue("ws:online_users", userId);
        if (instanceId == null) {
            // 用户不在线 → 离线处理
            // 用户不在线，触发离线提醒逻辑（短信、推送）
            //offlineNotifier.notify(toUserId, message);
            log.error("发送方离线 {}", userId);
            return;
        }
        // 处理收到的文本消息
        String clientMessage = message.getPayload();
        log.info("收到消息: {}", clientMessage);
        ChatMessageReq req = null;
        try {
            req = JSONUtil.toBean(clientMessage, ChatMessageReq.class);
        } catch (Exception e) {
            log.error("消息结构有误，请重新发送 {}", clientMessage);
            session.sendMessage(new TextMessage("消息结构有误，请重新发送: " + clientMessage));
            return;
        }

        if ("PING".equals(req.getType())) {
            redisService.setHashValue("ws:lastPing", userId, System.currentTimeMillis());
            session.sendMessage(new TextMessage("PING"));
            return;
        }

        req.setSenderId(Long.parseLong(userId));
        //机器人聊天
        if ("CHATBOT".equals(req.getType())) {
            this.handeChatBot(req);
            return;
        }
        this.sendInfo(req);
    }

    private void handeChatBot(ChatMessageReq req) throws IOException {
        WebSocketSession session = onlineSessions.get(req.getSenderId());
        if(session != null) {
            ReplyResponse replyResponse = conversationService.dialogBot(req.getMessage(), req.getSessionId());
            //返回给用户
            ChatMessageReq resp = new ChatMessageReq();
            resp.setType(req.getType());
            resp.setSenderId(-1L);
            resp.setReceiverId(req.getSenderId());
            resp.setMessage(replyResponse.getReplyContent());

            session.sendMessage(new TextMessage(JSONUtil.toJsonStr(resp)));

        }

        else {
            //当前用户websocket实例，不在本实例中维护
            log.info("当前用户websocket实例，不在本实例中维护 {}", req.getSenderId());
        }
    }

    /**
     * 给发送方发送消息
     *
     * @param req
     * @throws IOException
     */
    private void sendInfo(ChatMessageReq req) throws IOException {
        Long receiverId = req.getReceiverId();
        String receiverInstanceId = (String) redisService.getHashValue("ws:online_users", receiverId.toString());
        if (receiverInstanceId == null) {
            //保存离线消息
            log.info("接收方离线 {}", receiverId);
            chatMessageService.save(req);
            return;
        }
        String localInstanceId = System.getenv("INSTANCE_ID"); // 每个实例的唯一ID
        if (localInstanceId.equals(receiverInstanceId)) {
            WebSocketSession webSocketSession = onlineSessions.get(Long.parseLong(receiverId.toString()));
            req.setSenderId(MemberContextUtils.getCurrentUserId());
            //发给接收方
            webSocketSession.sendMessage(new TextMessage(JSONUtil.toJsonStr(req)));
            chatMessageService.save(req);
        } else {
            // 不在本实例 → 发到 MQ，由目标实例消费
            log.info("在其他实例中 。。。。。实例名称：{}", receiverInstanceId);

        }

    }


    /**
     * 然后通过定时任务定期清理长时间无心跳的连接：
     */
    @Scheduled(fixedDelay = 60000)
    @Async
    public void checkHeartbeat() {
        Map<Object, Object> lastPings = redisService.getHashEntries("ws:lastPing");
        long now = System.currentTimeMillis();
        int num = 0;
        for (Map.Entry<Object, Object> entry : lastPings.entrySet()) {
            long last = Long.parseLong(entry.getValue().toString());
            if (now - last > 5 * 60 * 1000) { // 超过5分钟无心跳
                redisService.delHashValue("ws:online_users", entry.getKey().toString());
                onlineSessions.remove(Long.parseLong(entry.getKey().toString()));
                num++;
            }
        }

        log.info("通过定时任务定期清理长时间无心跳的连接 num={}", num);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        // 连接关闭时调用
        log.info("WebSocket连接关闭: {}", session.getId());

        String userId = (String) session.getAttributes().get("userId");
        if (userId != null) {
            // 关键：连接关闭时移除会话
            onlineSessions.remove(Long.parseLong(userId));
            redisService.delHashValue("ws:online_users", userId);
        }
    }
}